package cn.loyle;

import com.xiaoleilu.hutool.io.FileUtil;
import com.xiaoleilu.hutool.io.file.FileWriter;
import com.xiaoleilu.hutool.util.StrUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        createAqFile("wxinv".toLowerCase(), "D:\\test\\");
    }

    public static void createAqFile(String aqName, String outPath) {
        File file = new File(new App().getClass().getResource("/").getPath() + "table.txt");
        File typeFile = FileUtil.touch(outPath + aqName + ".sql");
        File recieverFile = FileUtil.touch(outPath + StrUtil.upperFirst(aqName) + "Reciever" + ".java");
        File messageFile = FileUtil.touch(outPath + "QUEUE_MESSAGE_TYPE" + ".java");
        File ThreadProxyImpl = FileUtil.touch(outPath + "ThreadProxyImpl" + ".java");
//        File typeFile = new File(new App().getClass().getResource("/").getPath() + "TYPE.sql");
        boolean isBody = false;
        String tableName = null;
        Map<String, String> field = new LinkedHashMap<String, String>();
        String[] fieldNameAndType = new String[2];
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String text;
            while ((text = reader.readLine()) != null) {
                if (text.contains("create") && text.contains("table")) {
                    int start = text.indexOf("table");
                    tableName = text.substring(start + 5).trim();
//                    System.out.println("tableName:" + tableName);
                }
                if (text.equals(")")) {
                    isBody = false;
                }
                if (isBody) {
                    String[] split = text.split(" ");
                    int k = 0;
                    for (String s : split) {
                        if (!"".equals(s) && k < 2) {
                            fieldNameAndType[k] = s;
                            k++;
                        }
                    }
                    field.put(fieldNameAndType[0], fieldNameAndType[1]);
                }
                if (text.equals("(")) {
                    isBody = true;
                }
            }
            String typeText = "--创建类型\ncreate or replace type " + aqName + "type as object (\n" +
                    "oper VARCHAR2(4000),\n";
            String type = null;
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("number")) {
                    type = "NUMBER";
                } else {
                    type = "VARCHAR2(4000)";
                }
//                    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
                typeText += entry.getKey().toUpperCase() + " " + type + ",\n";
            }
            typeText = typeText.substring(0, typeText.length() - 2) + ")\n\n\n";
            System.out.println(typeText);
            String aqText = "--创建消息队列表\nbegin\ndbms_aqadm.create_queue_table(\n"
                    + "queue_table   => 'aq_" + aqName + "_table',--表名\n"
                    + "queue_payload_type => '" + aqName + "type',--类型\n"
                    + "multiple_consumers => false\n);\ndbms_aqadm.create_queue (--创建\n"
                    + "queue_name  => '" + aqName + "aq',\nqueue_table => 'aq_" + aqName + "_table'\n"
                    + ");\ndbms_aqadm.start_queue(--启动\nqueue_name  =>  '" + aqName + "aq'\n);\nend;\n\n\n";
            System.out.println(aqText);
            String procedureText = "--创建存储过程\n" +
                    "CREATE OR REPLACE PROCEDURE send_aq_msg_from_" + aqName + " (\n" +
                    "oper IN VARCHAR2,\n";
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("number")) {
                    type = "NUMBER";
                } else {
                    type = "VARCHAR2";
                }
                procedureText += entry.getKey().toUpperCase() + " IN " + type + ",\n";
            }
            procedureText = procedureText.substring(0, procedureText.length() - 2) + ")\n";
            procedureText += "as\nr_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;\n" +
                    "  r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;\n" +
                    "  v_message_handle RAW(16);\n" +
                    "  z_payload " + aqName + "type;\nbegin\nz_payload := " + aqName + "type(\n" +
                    "oper,\n";
            for (Map.Entry<String, String> entry : field.entrySet()) {
                procedureText += entry.getKey().toUpperCase() + ",\n";
            }
            procedureText = procedureText.substring(0, procedureText.length() - 2) + ");\n";
            procedureText += "dbms_aq.enqueue(\n" +
                    "    queue_name  => '" + aqName + "aq',\n" +
                    "    enqueue_options => r_enqueue_options,\n" +
                    "    message_properties => r_message_properties,\n" +
                    "    payload => z_payload,\n" +
                    "    msgid => v_message_handle\n" +
                    "  );\n" +
                    "  commit;\n" +
                    "end send_aq_msg_from_" + aqName + ";\n\n\n";
            System.out.println(procedureText);
            String insertTriggerText = "--创建INSERT触发器\n" +
                    "CREATE OR REPLACE TRIGGER " + aqName + "_INSERT_AQ_TRIGGER\n" +
                    "AFTER INSERT ON " + tableName + " FOR EACH ROW\n" +
                    "DECLARE\n" +
                    "pragma autonomous_transaction;\n" +
                    "BEGIN\nsend_aq_msg_from_" + aqName + "('0',";
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("date")) {
                    insertTriggerText += "to_char(:new." + entry.getKey() + ",'yyyy-mm-dd hh24:mi:ss'),\n";
                } else {
                    insertTriggerText += ":new." + entry.getKey() + ",\n";
                }
            }
            insertTriggerText = insertTriggerText.substring(0, insertTriggerText.length() - 2) + ");\n" +
                    "END;\n\n\n";

            System.out.println(insertTriggerText);
            String updateTriggerText = "--创建UPDATE触发器\n" +
                    "CREATE OR REPLACE TRIGGER " + aqName + "_UPDATE_AQ_TRIGGER\n" +
                    "AFTER UPDATE ON " + tableName + " FOR EACH ROW\n" +
                    "DECLARE\n" +
                    "pragma autonomous_transaction;\n" +
                    "BEGIN\nsend_aq_msg_from_" + aqName + "('1',";
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("date")) {
                    updateTriggerText += "to_char(:new." + entry.getKey() + ",'yyyy-mm-dd hh24:mi:ss'),\n";
                } else {
                    updateTriggerText += ":new." + entry.getKey() + ",\n";
                }
            }
            updateTriggerText = updateTriggerText.substring(0, updateTriggerText.length() - 2) + ");\n" +
                    "END;";

            System.out.println(updateTriggerText);
            String typeArrayText = "12,";
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("number")) {
                    typeArrayText += "2,";
                } else {
                    typeArrayText += "12,";
                }
            }
            typeArrayText = typeArrayText.substring(0,typeArrayText.length()-1);
            System.out.println(typeArrayText);

            FileWriter writer = new FileWriter(typeFile);
            writer.write(typeText +"\n/\n"+ aqText +"\n/\n" + procedureText +"\n/\n" + insertTriggerText +"\n/\n" + updateTriggerText);

            String reciever = "import java.util.Properties;\n" +
                    "\n" +
                    "import javax.jms.Message;\n" +
                    "import javax.jms.MessageConsumer;\n" +
                    "import javax.jms.MessageListener;\n" +
                    "import javax.jms.Queue;\n" +
                    "import javax.jms.QueueConnection;\n" +
                    "import javax.jms.QueueConnectionFactory;\n" +
                    "import javax.jms.Session;\n" +
                    "\n" +
                    "import cn.sinopharmtj.uilt.Util;\n" +
                    "import oracle.jms.AQjmsAdtMessage;\n" +
                    "import oracle.jms.AQjmsDestination;\n" +
                    "import oracle.jms.AQjmsFactory;\n" +
                    "import oracle.jms.AQjmsSession;\n" +
                    "\n" +
                    "\npublic class " + StrUtil.upperFirst(aqName) + "Reciever {\n" +
                    "\n" +
                    "    public static void startReciever() throws Exception {\n" +
                    "        String jdbcUrl = Util.getProperty(\"midurl\");\n" +
                    "        String username = Util.getProperty(\"miduser\");\n" +
                    "        String password = Util.getProperty(\"midpwd\");\n" +
                    "        QueueConnectionFactory queueConnectionFactory = AQjmsFactory\n" +
                    "                .getQueueConnectionFactory(jdbcUrl, new Properties());\n" +
                    "\n" +
                    "        QueueConnection conn = queueConnectionFactory.createQueueConnection(\n" +
                    "                username, password);\n" +
                    "        AQjmsSession session = (AQjmsSession) conn.createQueueSession(false,\n" +
                    "                Session.CLIENT_ACKNOWLEDGE);\n" +
                    "\n" +
                    "        conn.start();\n" +
                    "\n" +
                    "        Queue queue = (AQjmsDestination) session.getQueue(username,\n" +
                    "                \"" + aqName + "aq\");\n" +
                    "        AQjmsConsumer consumer = (AQjmsConsumer)session.createConsumer(queue, null,\n" +
                    "                QUEUE_MESSAGE_TYPE.getFactory(), null, false);\n" +
                    "\n" +
                    "        MessageListener listener = new MessageListener() {\n" +
                    "            public void onMessage(Message message) {\n" +
                    "\n" +
                    "                AQjmsAdtMessage adtMessage = (AQjmsAdtMessage) message;\n" +
                    "\n" +
                    "                try {\n" +
                    "                    QUEUE_MESSAGE_TYPE payload = (QUEUE_MESSAGE_TYPE) adtMessage\n" +
                    "                            .getAdtPayload();\n" +
                    "                    boolean bol = payload.getContent();\n" +
                    "                    if (bol) {\n" +
                    "                        adtMessage.acknowledge();// 确认消息接收完成\n" +
                    "                    }\n" +
                    "\n" +
                    "                } catch (Exception e) {\n" +
                    "                    e.printStackTrace();\n" +
                    "                }\n" +
                    "            }\n" +
                    "        };\n" +
                    "        DispatchScheduler scheduler = new AQjmsSimpleScheduler();\n" +
                    "        ThreadProxyImpl proxy = new ThreadProxyImpl();\n" +
                    "        consumer.setMessageListener(listener,scheduler,proxy);" +
                    "    }\n" +
                    "\n" +
                    "}";
            writer = new FileWriter(recieverFile);
            writer.write(reciever);


            String QUEUE_MESSAGE_TYPE = "import cn.sinopharmtj.cms.dao.NDao;\n" +
                    "import com.xiaoleilu.hutool.convert.Convert;\n" +
                    "import com.xiaoleilu.hutool.date.DateUtil;\n" +
                    "import oracle.jdbc.driver.OracleConnection;\n" +
                    "import oracle.jdbc.internal.OracleTypes;\n" +
                    "import oracle.jpub.runtime.MutableStruct;\n" +
                    "import oracle.sql.CustomDatum;\n" +
                    "import oracle.sql.CustomDatumFactory;\n" +
                    "import oracle.sql.Datum;\n" +
                    "import oracle.sql.STRUCT;\n" +
                    "\n" +
                    "import java.sql.SQLException;" +
                    "\n\n\npublic class QUEUE_MESSAGE_TYPE implements CustomDatum, CustomDatumFactory {\n" +
                    "    public static final String _SQL_NAME = \"QUEUE_MESSAGE_TYPE\";\n" +
                    "    public static final int _SQL_TYPECODE = OracleTypes.STRUCT;\n" +
                    "private NDao dao = new NDao();\n\n" +
                    "    MutableStruct _struct;\n" +
                    "    // 12表示字符串\n" +
                    "    static int[] _sqlType = {"+typeArrayText+"};\n" +
                    "\n" +
                    "    static CustomDatumFactory[] _factory = new CustomDatumFactory["+(field.size()+10)+"];\n" +
                    "    static final QUEUE_MESSAGE_TYPE _MessageFactory = new QUEUE_MESSAGE_TYPE();\n" +
                    "\n" +
                    "    public static CustomDatumFactory getFactory() {\n" +
                    "        return _MessageFactory;\n" +
                    "    }\n" +
                    "\n" +
                    "    public QUEUE_MESSAGE_TYPE() {\n" +
                    "        _struct = new MutableStruct(new Object["+(field.size()+10)+"], _sqlType, _factory);\n" +
                    "    }\n" +
                    "\n" +
                    "    public Datum toDatum(OracleConnection c) throws SQLException {\n" +
                    "        return _struct.toDatum(c, _SQL_NAME);\n" +
                    "    }\n" +
                    "\n" +
                    "    public CustomDatum create(Datum d, int sqlType) throws SQLException {\n" +
                    "        if (d == null)\n" +
                    "            return null;\n" +
                    "        QUEUE_MESSAGE_TYPE o = new QUEUE_MESSAGE_TYPE();\n" +
                    "        o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);\n" +
                    "        return o;\n" +
                    "    }\n" +
                    "\n" +
                    "\n" +
                    "    public boolean getContent() throws Exception {\n" +
                    StrUtil.upperFirst(aqName)+" "+aqName.toLowerCase()+" = new "+StrUtil.upperFirst(aqName)+"();\n";
            int k=1;
            for (Map.Entry<String, String> entry : field.entrySet()) {
                if (entry.getValue().toLowerCase().contains("number")) {
                    QUEUE_MESSAGE_TYPE+= aqName.toLowerCase()+".set"+StrUtil.upperFirst(entry.getKey())+"(Convert.toDouble(_struct.getAttribute("+ k++ +")));\n";
                }else if (entry.getValue().toLowerCase().contains("date")) {
                    QUEUE_MESSAGE_TYPE+= aqName.toLowerCase()+".set"+StrUtil.upperFirst(entry.getKey())+"(DateUtil.parse((String)_struct.getAttribute("+ k++ +")));\n";
                }else {
                    QUEUE_MESSAGE_TYPE += aqName.toLowerCase()+".set" + StrUtil.upperFirst(entry.getKey()) + "(Convert.toStr(_struct.getAttribute(" + k++ + ")));\n";
                }
            }

                    QUEUE_MESSAGE_TYPE+= "        String oper = Convert.toStr(_struct.getAttribute(0));\n" +
                            "try {\n" +
                            "            if (\"0\".equals(oper)) {\n" +
                            "                dao.insert" + StrUtil.upperFirst(aqName) + "("+aqName.toLowerCase()+");\n" +
                            "            }else {\n" +
                            "                dao.update" + StrUtil.upperFirst(aqName) + "("+aqName.toLowerCase()+");\n" +
                            "            }\n" +
                            "            return true;\n" +
                            "        }catch (Exception e){\n" +
                            "            return false;\n" +
                            "        }" +
                    "    }\n" +
                    "\n" +
                    "}";

            writer = new FileWriter(messageFile);
            writer.write(QUEUE_MESSAGE_TYPE);

            String publicClass = "import oracle.jms.ThreadProxy;\n" +
                    "\n" +
                    "public class ThreadProxyImpl implements ThreadProxy {\n" +
                    "\n" +
                    "    public Thread launch(Runnable runnable) throws Exception {\n" +
                    "        Thread thread = new Thread(runnable);\n" +
                    "\n" +
                    "        thread.start();\n" +
                    "        return thread;\n" +
                    "    }\n" +
                    "}";

            writer = new FileWriter(ThreadProxyImpl);
            writer.write(procedureText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
